﻿using com.kmer;
using com.kmer.ApiServer;
using com.kmer.ApiServer.Attributes;
using com.kmer.ApiServer.com.kmer.Model;
using com.kmer.Attributes;
using com.kmer.Cache;
using com.kmer.db;
using com.kmer.Helper;
using com.kmer.interfaces;
using com.kmer.library.Factorys;
using com.kmer.models;
using System;
using System.ComponentModel;
using System.Linq;

namespace BaseAPI
{
    /// <summary>
    /// 登陆API
    /// </summary>
    public class LoginHandler : BaseHandler
    {
        #region 属性
        private IUserFactory userFactory = FactoryMaker.Get<IUserFactory>("user-facotry", "com.kmer.db.MemberShipFactory,com.kmer.db");
        private km_platformEntities db_context;
        private const string DEVICEID_KEY = "DeviceId:";

        #endregion

        #region 构造函数
        public LoginHandler()
        {
            db_context = new km_platformEntities();
        }
        #endregion

        #region API
        /// <summary/> 
        /// <param name="UserName">用户名（LoginID）</param>
        /// <param name="PassWord">MD5以后的密码</param>
        /// <returns></returns>
        [Description("账号登陆")]
        [ReturnType(typeof(LoginUserData))]
        public ApiResult Login([ParamDescription("用户账号")]string UserName, [ParamDescription("用户密码（MD5）")]string PassWord, [ParamDescription("设备ID")] string DeviceId)
        {
            var loginUser = userFactory.Login(UserName, PassWord);
            if (loginUser == null)
            {
                return Error("用户名或密码错误！");
            }

            if (string.IsNullOrEmpty(DeviceId))
            {
                return Error("设备编码不能为空！");
            }
            //检查是否在线
            if (CheckUserOnline(loginUser.CusId, DeviceId))
            {
                return Error("用户已经在线，不能重复登陆！");
            }
            var login_user_data = CreateUserData(loginUser, DeviceId);
            //缓存用户数据
            SetCacheLoginUserData(login_user_data);
            return Success(login_user_data);
        }

        /// <summary>
        /// 清除缓存获取最新的登陆用户数据
        /// </summary>
        /// <returns></returns>
        [MustLogin]
        [Description("刷新登陆用户数据")]
        [ReturnType(typeof(LoginUserData))]
        public ApiResult RefreshLoginUserData(string DeviceId)
        {
            //删除CacheUserkey
            ClearCache(DeviceId);
            var loginUser = userFactory.GetUserByUserID(CusID);
            var login_user_data = CreateUserData(loginUser, DeviceId);
            SetCacheLoginUserData(login_user_data);
            return Success(login_user_data);
        }

        /// <summary>
        /// 退出登陆
        /// </summary>
        /// <returns></returns>
        [MustLogin]
        [Description("退出系统")]
        public ApiResult LoginOut([ParamDescription("设备ID")] string DeviceId)
        {
            try
            {
                ClearCache(DeviceId);
            }
            catch (Exception ex)
            {
                return Error(ex.Message);
            }
            return Success(0);
        }
        #endregion

        #region 私有方法

        /// <summary>
        /// 检查用户在线
        /// </summary>
        /// <returns></returns>
        private bool CheckUserOnline(int cusId, string deviceId)
        {
            bool result = false;
            string key = CacheUserkey(cusId);
            var exists = RedisCache.Exists(key);
            if (exists)
            {
                var userData = CacheLoginUserData(cusId);
                //在不同的设备上有登陆
                if (userData.DeviceId != deviceId)
                {
                    result = true;
                }
                else
                {
                    ClearCache(deviceId);
                    result = false;
                }
            }
            return result;
        }

        /// <summary>
        /// 返回用户所属公司
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        private string GetCompany(int userId)
        {

            #region 从向拄下找,一般是集团用户
            var sql1 = $@"--查询树状结构某节点下的所有子节
                        with cte_child(deptid,parentid,DeptContent,CompanyID)
                        as
                        (
                            --起始条件 
                            select deptid,parentid,DeptContent,CompanyID
                            from sys_dept
                            where deptcode = (SELECT d.DeptCode FROM dbo.sys_users u
                            INNER JOIN dbo.sys_dept d ON u.DeptID=d.DeptID
                             WHERE UserID={userId}) --列出父节点查询条件
                            AND IsRemove=0
                            union all
                            --递归条件
                            select a.deptid,a.parentid,a.DeptContent,a.CompanyID
                            from sys_dept a
                            inner join 
                            cte_child b
                            on ( a.ParentID=b.deptid)  --根据查询到的父节点(a.Parent)，通过CTE递归查询出其子节点(b.ID)
                        )
                        select CompanyID,DeptContent from cte_child where ParentID =1 AND CompanyID IS NOT NULL ;";
            #endregion

            #region 从下往上往，一般是公司下的用户
            var sql2 = $@"--查询树状结构某节点下的所有子节
                        with cte_child(deptid,parentid,DeptContent,CompanyID)
                        as
                        (
                            --起始条件 
                            select deptid,parentid,DeptContent,CompanyID
                            from sys_dept
                            where deptcode = (SELECT d.DeptCode FROM dbo.sys_users u
                            INNER JOIN dbo.sys_dept d ON u.DeptID=d.DeptID
                             WHERE UserID={userId}) --列出父节点查询条件
                            AND IsRemove=0
                            union all
                            --递归条件
                            select a.deptid,a.parentid,a.DeptContent,a.CompanyID
                            from sys_dept a
                            inner join 
                            cte_child b
                            on ( a.deptid=b.ParentID)  --根据查询到的父节点(a.Parent)，通过CTE递归查询出其子节点(b.ID)
                        )
                        select CompanyID,DeptContent from cte_child where ParentID =1 AND CompanyID IS NOT NULL;";
            #endregion

            var query1 = db_context.Database.SqlQuery<CompanyData>(sql1);
            var query2 = db_context.Database.SqlQuery<CompanyData>(sql2);
            //合并两个集合并去重
            var result = query1.Union(query2).Distinct().ToList();
            return result.FirstOrDefault()?.CompanyID;
        }

        /// <summary>
        /// 创建登陆用户数据
        /// </summary>
        /// <param name="loginUser"></param>
        /// <returns></returns>
        private LoginUserData CreateUserData(User loginUser, string deviceId)
        {
            //用户头像
            var avatar_url = db_context.vm_Avatar.FirstOrDefault(c => c.UserID == loginUser.CusId)?.Url;
            var userToken = OnlineUsers.GetUserToken(loginUser.CusId);
            var company = GetCompany(loginUser.CusId);
            var orderUser = db_context.t_order_userweight.FirstOrDefault(p => p.UserID == loginUser.CusId && p.CompanyID == company);
            //string ipAddress = Request.ServerVariables.Get("Remote_Host").ToString();
            //保存当前设备ID
            RedisCache.AddString(DEVICEID_KEY + deviceId, userToken, Timeout);
            //保存当前用户
            RedisCache.AddInt(USERTOKEN_KEY + userToken, loginUser.CusId, Timeout);
            //维护在线用户
            //OnlineUsers.AddAndRefresh(loginUser.CusId, loginUser.RealName);
            //缓存公司名称 
            //RedisCache.AddString(COMPANY_KEY + userToken, company, Timeout);
            var loginUserData = new LoginUserData
            {
                CusID = loginUser.CusId,
                NickName = loginUser.NickName,
                LoginID = loginUser.LoginId,
                Avatar = this.GetImageUrl(avatar_url, "http"),
                Tel = loginUser.Tel,
                AccessToken = userToken,
                SetVersion = orderUser != null && (orderUser.SetVersion ?? false),
                Grade = orderUser != null && (orderUser.Grade ?? false),
                Management = orderUser != null && (orderUser.Management ?? false),
                TakePhoto = orderUser != null && (orderUser.TakePhotos ?? false),
                DeviceId = deviceId,
                CompanyID = company
            };
            return loginUserData;
        }

        /// <summary>
        /// 清除缓存
        /// </summary>
        [Description("清除缓存")]
        private void ClearCache(string deviceId)
        {
            string d_key = string.Empty; //设备key
            string u_key = string.Empty; //用户key
            //string c_key = string.Empty; //公司key
            string u_d_key = string.Empty; //用户数据key
            if (!string.IsNullOrEmpty(deviceId))
            {
                d_key = DEVICEID_KEY + deviceId;
                if (RedisCache.Exists(d_key))
                {
                    string userToken = RedisCache.GetString(d_key);
                    u_key = USERTOKEN_KEY + userToken;
                    //c_key = COMPANY_KEY + userToken;
                    int cuid = RedisCache.GetInt(u_key, 0);
                    u_d_key = CacheUserkey(cuid);

                    if (RedisCache.Exists(u_d_key))
                    {
                        OnlineUsers.RemoveUser(cuid);
                        RedisCache.Remove(u_d_key);
                    }
                    if (RedisCache.Exists(u_key))
                    {
                        RedisCache.Remove(u_key);
                    }
                    RedisCache.Remove(d_key);
                }
            }
            else
            {
                u_key = USERTOKEN_KEY + UserToken;
                //c_key = COMPANY_KEY + UserToken;
                //删除UserToken
                if (RedisCache.Exists(u_key))
                {
                    if (RedisCache.Exists(CacheUserkey()))
                    {
                        RedisCache.Remove(CacheUserkey());
                    }
                    OnlineUsers.RemoveUser(CusID);
                    //删除CacheUserkey
                    RedisCache.Remove(u_key);
                }
            }
        }
        #endregion
    }
}
